package org.hiucung.orangeappupdater.updater.net;

import android.os.Handler;
import android.os.Looper;
import android.util.Log;

import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

/**
 * okhttp网络管理器，实现INetManager三个方法
 */
public class OkHttpNetManager implements INetManager{

    private static OkHttpClient sOkHttpClient;
    private static Handler sHandler = new Handler(Looper.getMainLooper());
    static {
        //在静态代码块中完成初始化
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        builder.connectTimeout(15, TimeUnit.SECONDS);
        sOkHttpClient = builder.build();

        //默认是http
        //如果是https，需要做ssl签名证书、遇到握手的错误
        //builder.sslSocketFactory()
    }

    @Override
    public void get(String url,final INetCallBack callBack, Object tag) {
        Request.Builder builder = new Request.Builder();
        Request request = builder.url(url).get().tag(tag).build();
        Call call = sOkHttpClient.newCall(request);
        call.enqueue(new Callback() {//异步操作
            @Override
            public void onFailure(final Call call, final IOException e) {
                // 我们需要不在这里直接做 UI 上的变动，所以我们需要一个handler
                sHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        callBack.failed(e);
                    }
                });
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                try {
                    String result = response.body().string();
                    sHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            callBack.success(result);
                        }
                    });
                }catch (Throwable e){
                    e.printStackTrace();
                    callBack.failed(e);
                }
            }
        });
    }

    @Override
    public void download(String url, File targetFile, INetDownloadCallBack callBack, Object tag) {
        if (!targetFile.exists()){
            targetFile.getParentFile().mkdirs();
        }
        Request.Builder builder = new Request.Builder();
        Request request = builder.url(url).get().tag(tag).build();
        Call call = sOkHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                callBack.failed(e);
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {

                InputStream inputStream = null;//初始化输入输出流
                OutputStream outputStream = null;
                try {
                    final long totalLength = response.body().contentLength();//初始化总长度

                    inputStream = response.body().byteStream();//输入流来自网络的字节流
                    outputStream  = new FileOutputStream(targetFile);//输出到本地文件中

                    byte[] buffer = new byte[8 * 1024];
                    long currentLength = 0;
                    int bufferLength = 0;

                    while (!call.isCanceled() && (bufferLength = inputStream.read(buffer)) != -1) {
                        outputStream.write(buffer, 0, bufferLength);
                        outputStream.flush();
                        currentLength += bufferLength;

                        final long finalCurrentLength = currentLength;//用于保存数字进度
                        sHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                callBack.progress((int) (finalCurrentLength * 1.0f / totalLength * 100));
                            }
                        });
                    }

                    //不加判断的话，getActivity回调callback会报错
                    //如果call被取消了话直接return，不往下执行
                    if (call.isCanceled()){
                        return;
                    }

                    try {
                        //把文件暴露给别的进程访问，设置权限。当然如果是给sdcard就不需要这样的操作
                        targetFile.setExecutable(true,false);
                        targetFile.setReadable(true,false);
                        targetFile.setWritable(true,false);
                    } catch (Exception e){
                        e.printStackTrace();
                    }

                    sHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            callBack.success(targetFile);
                        }
                    });
                } catch (final Throwable e){
                    //不加判断的话，getActivity回调callback会报错
                    //如果call被取消了话直接return，不往下执行
                    if (call.isCanceled()){
                        return;
                    }
                    e.printStackTrace();
                    sHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            callBack.failed(e);
                        }
                    });
                }finally {
                    if (inputStream != null){
                        inputStream.close();
                    }
                    if (outputStream != null){
                        outputStream.close();
                    }
                }

            }
        });
    }

    @Override
    public void cancel(Object tag) {

        //正在排队的calls列表
        List<Call> queuedCalls = sOkHttpClient.dispatcher().queuedCalls();

        if (queuedCalls!=null){
            for (Call call : queuedCalls) {
                if (tag.equals(call.request().tag())){
                    Log.d("hiucung","find call = " + tag);
                    call.cancel();
                }
            }
        }

        //正在执行的calls列表
        List<Call> runningCalls = sOkHttpClient.dispatcher().runningCalls();

        if (runningCalls != null){
            for (Call call : runningCalls) {
                if (tag.equals(call.request().tag())){
                    Log.d("hiucung","find call = " + tag);
                    call.cancel();
                }
            }
        }
    }
}
